<!--
 * @Author: CarlYang
 * @Date: 2021-08-02 16:06:01
 * @LastEditTime: 2021-08-03 09:13:47
 * @LastEditors: DESKTOP-PNCL084
 * @Description: 树形组件
 * @FilePath: \vue-g6\src\components\TreeCanvas\index.vue
-->
<template>
  <el-container class="container">
    <el-row class="container">
      <el-col
        :xs="24"
        :sm="24"
        :md="16"
        :lg="18"
        :xl="20"
        class="full-height">
        <!-- ============================================= 画布视图 ============================================= -->
        <div
          :id="canvasId"
          :class="canvasClass"
          :style="canvasStyle"
          :ref="canvasRef"></div>
      </el-col>
      <el-col
        :xs="24"
        :sm="24"
        :md="8"
        :lg="6"
        :xl="4"
        class="full-height">
        <!-- ============================================= 树形布局配置 ============================================= -->
        <div class="tree-setting">
          <el-card class="box-card">
            <div slot="header" class="clearfix">
              <span>树形布局设置</span>
            </div>
            <el-form ref="treeForm" :model="treeForm" label-width="80px">
              <el-form-item label="树方向">
                <el-select v-model="treeForm.direction" placeholder="请选择数方向">
                  <el-option label="自上而下" value="UD"></el-option>
                  <el-option label="自下而上" value="DU"></el-option>
                  <el-option label="自左而右" value="LR"></el-option>
                  <el-option label="自右而左" value="RL"></el-option>
                </el-select>
              </el-form-item>
              <el-form-item label="层级距">
                <el-input v-model="treeForm.distY" type="number"></el-input>
              </el-form-item>
              <el-form-item label="点间距">
                <el-input v-model="treeForm.distX" type="number"></el-input>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" @click="applyLayout(true)">应用设置</el-button>
              </el-form-item>
            </el-form>
          </el-card>
        </div>
      </el-col>
    </el-row>
  </el-container>
</template>

<script>
/* eslint-disable */
import VisGraph from '@/assets/js/GraphVis/old/visgraph.min.js'
import LayoutFactory from '@/assets/js/GraphVis/old/visgraph-layout.min.js'
export default {
  name: 'TreeCanvas',
  props: {
    // 画布id
    canvasId: {
      type: String,
      default: 'graph-container'
    },
    // 画布class
    canvasClass: {
      type: String,
      default: 'graph-container'
    },
    // 画布ref
    canvasRef: {
      type: String,
      default: 'graphContainer'
    },
    // 画布样式
    canvasStyle: {
      type: Object,
      default: () => {
        return {
          width: '100%',
          height: '100%'
        }
      }
    },
    // 节点的默认配置
    canvasConfig: {
      type: Object,
      default: () => {
        return {}
      }
    },
    // 图谱数据
    graphData: {
      type: Object,
      default: () => {}
    }
  },
  components: {
    VisGraph,
    LayoutFactory
  },
  data () {
    return {
      visgraph: null,
      treeForm: {
        direction: 'UD',
        distY: 300,
        distX: 200
      }
    }
  },
  mounted () {
    this.createCanvas()
    window.onresize = () => {
      if (this.visgraph) {
        this.visgraph.setZoom()
      }
    }
  },
  methods: {
    /**
     * 创建画布实例
     * @date 2021-08-02
     */
    createCanvas () {
      const _this = this
      // 节点点击
      this.canvasConfig.node.onClick = function(event, node) {
        if(node.contract && node.contract == 1){
          node.contract=0;
          node.tipText=null;
          _this.expendChild(node);
        }else{
          node.contract=1;
          _this.contractChild(node);
        }
      }
      // 节点双击
      this.canvasConfig.node.ondblClick = function(event, node) {
        // if(node.contract && node.contract == 1){
        //   node.contract=0;
        //   node.tipText=null;
        //   _this.expendChild(node);
        // }else{
        //   node.contract=1;
        //   _this.contractChild(node);
        // }
      }
      this.visgraph = new VisGraph(
        document.getElementById(this.canvasId),
        this.canvasConfig
      )
      this.visgraph.clearAll()
      console.log(this.graphData)
      this.visgraph.drawData(this.graphData)
      this.autoLayout()
      this.visgraph.moveCenter()
    },
    /**
     * 自动布局
     * @date 2021-08-02
     */
    autoLayout (distX, distY, direction) {
      const visdata = this.visgraph.getVisibleData()
      const nodeCoords = new Map()
      visdata.nodes.forEach((n)=>{
        nodeCoords.set(n.id,{x:n.x,y:n.y})
      })
      
      const layout=new LayoutFactory(visdata).createLayout("tree")
      layout.boolTransition = false // 不加动画	
      layout.resetConfig({
        distX: distX || 200,
        distY: distY || 300,
        direction: direction || 'UD'
      })
      layout.runLayout()
      
      visdata.nodes.forEach((n)=>{
        let targetX=n.x,
            targetY=n.y
        const nodePos = nodeCoords.get(n.id)
        n.x = nodePos.x
        n.y = nodePos.y
        n.visible = true
        const inlinks = n.inLinks || []
        inlinks.forEach((link) => {
          link.visible = true
        })
        
        this.visgraph.animate({
          targets: n,
          x: targetX,
          y: targetY,
          alpha: 1,
          duration: 800,
          easing: 'easeOutQuad',
          update: () => {
            this.visgraph.setZoom('auto')
          }
        })
      })
    },
    /**
     * 查找所有子节点
     * @date 2021-08-02
     * @param {Object} node
     * @param {Array} allChildNodes
     * @returns {any}
     */
    deepFindChildNode (node, allChildNodes) {
      const outLinks = node.outLinks||[]
      const childNodes = outLinks.map((link)=>{
        return link.target
      })
      childNodes.forEach((n)=>{
        allChildNodes.push(n)
      })
      childNodes.forEach((n)=>{
        if(!n.contract){
          this.deepFindChildNode(n, allChildNodes)
        }
      })
    },
    /**
     * 节点展开
     * @date 2021-08-02
     * @param {Object} node
     */
    expendChild (node) {
      const allChildNodes = []
      this.deepFindChildNode(node, allChildNodes)
      if(allChildNodes.length > 0){
        //1、所有子节点显示，并且重新布局
        allChildNodes.forEach((n)=>{
          var targetX = n.x,targetY=n.y;
          n.x=node.x;
          n.y=node.y;
          n.visible = true;
          n.alpha = 0.1;
        });
        this.applyLayout(false)
      }
    },
    /**
     * 节点收缩
     * @date 2021-08-02
     * @param {Object} node
     */
    contractChild(node){
      const allChildNodes = []
      this.deepFindChildNode(node,allChildNodes)
      
      if(allChildNodes.length > 0){
        //设置提示信息
        node.tipText= ' ' + allChildNodes.length + ' '
        
        allChildNodes.forEach((n)=>{
          if(n.visible == 1){
            let targetX=node.x,
                targetY=node.y;
            this.visgraph.animate({
              targets: n,
              x: targetX,
              y: targetY,
              alpha:0,
              duration: 1000,
              easing: 'easeInOutQuad',
              complete: () => {
                n.visible = false;
                (n.inLinks||[]).forEach(function(link){
                  link.visible = false;
                })
                this.applyLayout(false)
              }
            });
          }
        });
      }
    },
    /**
     * 应用设置操作
     * @date 2021-08-02
     * @param {Boolean} changeLineType
     * @returns {any}
     */
    applyLayout(changeLineType) {
      this.autoLayout(this.treeForm.distX, this.treeForm.distY, this.treeForm.direction)
      if(changeLineType){
        const lineTypeMap={
          'UD':'vbezier',
          'DU':'vlink',
          'LR':'hlink',
          'RL':'hbezier'
        }
        
        this.visgraph.links.forEach((l)=>{
          l.lineType=lineTypeMap[this.treeForm.direction]
        })
      }
    }
  },
  destroyed () {
    this.visgraph = null
  }
}
</script>

<style lang="scss" scoped>
/* 宽高都为100% */
.container {
  width: 100%;
  height: 100%;
}
.full-height {
  height: 100%;
}
.tree-setting {
  height: 100%;
  .box-card {
    height: 100%;
  }
}
</style>
